﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;

namespace LibraryEA
{
    public class EArchitect
    {
        private string caminho = string.Empty;
        private EA.Repository repository = null;
        public List<Classe> classesEA = new List<Classe>();
        public List<Diagrama> diagramasEA = new List<Diagrama>();
        //string nome_namespace = string.Empty;
        string nome_namespace_base = string.Empty;
        public List<string> errosEA = new List<string>();

        public EArchitect(string caminho) 
        {
            this.caminho = caminho;
            repository = new EA.RepositoryClass();
            repository.OpenFile(this.caminho);
        }

        public void FecharEA()
        {
            repository.CloseFile();
            repository.CloseAddins();
            Marshal.ReleaseComObject(repository);
            GC.Collect();
        }

        public List<string> RetornaModulos() 
        {
            List<string> lista = new List<string>();
            

            foreach (EA.Package package in repository.Models)
            {
                foreach (EA.Package pkg in package.Packages)
                {
                    lista.Add(package.Name);
                }
            }

            return lista;
        }

        public EA.Package AbrirModulo(string packageName, string modulo, string arquitetura)
        {
            List<string> lista= new List<string>();

            nome_namespace_base = "Sinacor." + packageName + "." + modulo + ".";
            //nome_namespace = nome_namespace_base;

            foreach (EA.Package package in repository.Models) 
            {
                foreach(EA.Package pkg in package.Packages)
                {
                    if(pkg.Name.ToLower() == packageName.ToLower()) 
                    {
                        return pkg;
                    }
                }

                foreach (EA.Package pkg in package.Packages)
                {
                    string name = pkg.Name;
                    foreach (EA.Package pkgInterna in pkg.Packages)
                    {
                        if(pkgInterna.Name.ToLower() == packageName.ToLower() && arquitetura.ToLower() == pkg.Name.ToLower())
                        {
                            return pkgInterna;
                        }

                        foreach(EA.Package pkgInterna2 in pkgInterna.Packages)
                        {
                            if(pkgInterna2.Name.ToLower() == packageName.ToLower() && arquitetura.ToLower() == pkgInterna.Name.ToLower())
                            {
                                return pkgInterna2;
                            }
                        }
                    }
                }


                
            }

            //modelo site BVMF
            foreach(EA.Package package in repository.Models)
            {
                foreach(EA.Package pkg in package.Packages)
                {
                    if(pkg.Name.ToLower() == packageName.ToLower())
                    {
                        return pkg;
                    }
                }

                foreach(EA.Package pkg in package.Packages)
                {
                    string name = pkg.Name;
                    foreach(EA.Package pkgInterna in pkg.Packages)
                    {
                        if(pkgInterna.Name.ToLower() == packageName.ToLower())
                        {
                            return pkgInterna;
                        }

                        foreach(EA.Package pkgInterna2 in pkgInterna.Packages)
                        {
                            if(pkgInterna2.Name.ToLower() == packageName.ToLower())
                            {
                                return pkgInterna2;
                            }
                        }
                    }
                }



            }

            return null;

        }

        public void AbrirClasses(EA.Package pkg)
        {
            List<string> classes = new List<string>();
            foreach (EA.Package pkgInterna in pkg.Packages)
            {
                RetornaClasses(pkgInterna,nome_namespace_base);
            }

            
        }

        private void RetornaClasses(EA.Package pkgInterna, string nome_namespace_pai)
        {
            string nome_namespace = nome_namespace_pai + pkgInterna.Name.Replace(" ","") + ".";
            if (VerificaNamespace(pkgInterna.Name))
                nome_namespace_pai = nome_namespace;
            else
                nome_namespace = nome_namespace_pai;


            foreach(EA.Diagram diagram in pkgInterna.Diagrams)
            {
                Diagrama diagrama = new Diagrama();
                diagrama.contador = diagram.DiagramObjects.Count;
                diagrama.nome = diagram.Name;
                diagrama.namespace_string = nome_namespace.TrimEnd('.');

                if(diagrama.contador <= 10)
                    diagrama.tipoRegra = Diagrama.TipoRegra.Facil;
                else if(diagrama.contador <= 20)
                    diagrama.tipoRegra = Diagrama.TipoRegra.Medio;
                else if(diagrama.contador <= 30)
                    diagrama.tipoRegra = Diagrama.TipoRegra.Dificil;
                else if(diagrama.contador <= 40)
                    diagrama.tipoRegra = Diagrama.TipoRegra.Avancado;
                this.diagramasEA.Add(diagrama);

            }

            if (pkgInterna.Elements.Count > 0)
            {

                


                foreach (EA.Element element in pkgInterna.Elements)
                {
                    if (element.Name != string.Empty)
                    {
                        List<string> errosPossiveis = new List<string>();

                        Classe classe = new Classe();
                        classe.nome = element.Name;
                        classe.tipo = element.Stereotype;
                        classe.metatype = element.MetaType;
                        classe.nome_namespace = nome_namespace.TrimEnd('.');

                        foreach (EA.Attribute att in element.Attributes)
                        {
                            if (att.Type == string.Empty && classe.nome_namespace.IndexOf("Enum") == -1)
                                errosPossiveis.Add("Possível Erro na criação de atributos. Atributo sem tipo:" + classe.nome_namespace + "." +  element.Name + "." + att.Name);

                            classe.atributos.Add(new Classe.Atributo() { nome = att.Name, tipo = att.Type, notes = ReplaceHTML(att.Notes) });
                        }

                        foreach (EA.Method met in element.Methods)
                        {
                            if (met.Stereotype == "property")
                            {
                                if (met.ReturnType == string.Empty)
                                    errosPossiveis.Add("Possível Erro na criação de propriedades. Propriedade sem tipo:" + classe.nome_namespace + "." + element.Name + "." + met.Name);

                                classe.propriedades.Add(new Classe.Propriedade() { nome = met.Name, tipo = met.ReturnType, notes = ReplaceHTML(met.Notes) ,rulesets = met.Style});
                            }
                            else
                            {


                                Classe.Metodo metodo = new Classe.Metodo();
                                metodo.nome = met.Name;
                                metodo.retorno = met.ReturnType;
                                metodo.notes = ReplaceHTML(met.Notes);
                                metodo.scope = met.Visibility.ToLower();
                                metodo.behavior = met.Behavior;

                                if (met.ReturnType == string.Empty)
                                    errosPossiveis.Add("Possível Erro na criação de Método. Método sem retorno:" + classe.nome_namespace + "." + element.Name + "." + met.Name);

                                if (met.Visibility == string.Empty)
                                    errosPossiveis.Add("Possível Erro na criação de Método. Método sem escopo:" + classe.nome_namespace + "." + element.Name + "." + met.Name);

                                foreach (EA.Parameter p in met.Parameters)
                                {
                                    if (p.Name != string.Empty)
                                        metodo.parametros += p.Type + " " + p.Name + ",";
                                    else
                                        metodo.parametros += p.Type + " parameter" + ",";
                                }
                                if (metodo.parametros != null)
                                    metodo.parametros = metodo.parametros.TrimEnd(',');

                                classe.metodos.Add(metodo);
                            }

                        }
                        classe.errosPossiveis = errosPossiveis;
                        classesEA.Add(classe);
                    }
                }

            }

            if (pkgInterna.Packages.Count > 0)
            {
                foreach (EA.Package pkgi in pkgInterna.Packages)
                {
                    RetornaClasses(pkgi, nome_namespace);
                }
            }



        }

        private bool VerificaNamespace(string nomePackage)
        {
            if (nomePackage.IndexOf("Diagrama-") >= 0)
                return false;
            if (nomePackage.IndexOf("Diagrama -") >= 0)
                return false;
            if (nomePackage == "Servico")
                return false;
            if (nomePackage == "UI")
                return false;
            if (nomePackage == "Servicos")
                return false;

            return true;
        }

        private string ReplaceHTML(string p)
        {
            Regex objRegExp = new Regex("<(.|\n)+?>");
            string ret = objRegExp.Replace(p, "");
            return ret;
        }




        internal EA.Package AbrirModulo(string packageName, string modulo)
        {
            List<string> lista = new List<string>();

            nome_namespace_base = "Sinacor." + packageName + "." + modulo + ".";
            //nome_namespace = nome_namespace_base;

            foreach(EA.Package package in repository.Models)
            {
                foreach(EA.Package pkg in package.Packages)
                {
                    if(pkg.Name.ToLower() == packageName.ToLower())
                    {
                        return pkg;
                    }
                }


            }

            return null;
        }
    }
}
